#include "common.h"
#include <stdlib.h>

int copy_part(FILE *src, long origin, long end, FILE *out) {
	if(src == NULL || out == NULL) {
		return -1;
	}

	if(origin >= end) {
		return 0;
	}

	// mark the previous file position indicator
	long previous_pos = ftell(src);

	const buffer_size = 512;
	char *buffer = (char*)malloc(buffer_size);

	long copy_size = end - origin + 1;
	int steps = copy_size / buffer_size + 1;
	int i;
	// move the file position indicator to origin
	fseek(src, origin, SEEK_SET);
	for(i = 0; i < steps - 1; ++i) {
		if(fread(buffer, 1, buffer_size, src) == buffer_size) {
			if(fwrite(buffer, 1, buffer_size, out) != buffer_size) {
				// recover the previous file position indicator
				fseek(src, previous_pos, SEEK_SET);
				free(buffer);
				return -1;
			}
		} else {
			// recover the previous file position indicator
			fseek(src, previous_pos, SEEK_SET);
			free(buffer);
			return -1;
		}
	}

	int rest_size = copy_size % buffer_size;
	if(fread(buffer, 1, rest_size, src) == rest_size) {
		if(fwrite(buffer, 1, rest_size, out) != rest_size) {
			// recover the previous file position indicator
			fseek(src, previous_pos, SEEK_SET);
			free(buffer);
			return -1;
		}
	} else {
		// recover the previous file position indicator
		fseek(src, previous_pos, SEEK_SET);
		free(buffer);
		return -1;
	}
	// recover the previous file position indicator
	fseek(src, previous_pos, SEEK_SET);
	free(buffer);
	return copy_size;
}
int write_short(FILE *out, short num, int le) {
	if (le) {
		if (fwrite(&num, sizeof(short), 1, out) != sizeof(int)) {
			return -1;
		}
	}
	else {
		short num_reverse = reverse_int16(num);
		if (fwrite(&num_reverse, 2, 1, out) != 1) {
			return -1;
		}
		return 0;
	}
}
int write_int(FILE *out, int num, int le) {
	if(le) {
		if(fwrite(&num, sizeof(int), 1, out) != sizeof(int)) {
			return -1;
		}
	} else {
		/*
		int size = sizeof(int);
		int *big_endian = malloc(size);
		int i;
		for(i = 0; i < size; ++i) {
			big_endian[i] = num >> ((size - i - 1) * 8);
			if(fwrite(&big_endian[i], 1, 1, out) != 1) {
				return -1;
			}
		}
		free(big_endian);
		*/
		int num_reverse = reverse_int32(num);
		if(fwrite(&num_reverse, 4, 1, out) != 1) {
			return -1;
		}
		return 0;
	}
}

int reverse_int32(int int32) {
	return ((int32 & 0xFF000000) >> 24) | ((int32 & 0x00FF0000) >> 8) | ((int32 & 0x0000FF00) << 8) | ((int32 & 0x000000FF) << 24);
}
short reverse_int16(short int16) {
	return ((int16 & 0xFF00) >> 8) | ((int16 & 0x00FF) << 8);
}
